﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using WHLRDF.Log;

namespace WHLRDF
{
    public class SendHttpHelper
    {
        public static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            //直接确认，否则打不开    
            return true;
        }

        public static bool XmlPost(string xml, string url, string certPath, string certPwd, int timeout, ref string strResult)
        {
            var start = Environment.TickCount;
            var logModel = GetRequestLogModel(url, xml, true);
            //System.GC.Collect();//垃圾回收，回收没有正常关闭的http连接
            HttpWebRequest request = null;
            HttpWebResponse response = null;
            Stream reqStream = null;
            try
            {
                //设置最大连接数
                ServicePointManager.DefaultConnectionLimit = 200;
                //设置https验证方式
                if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
                {
                    ServicePointManager.ServerCertificateValidationCallback =
                            new RemoteCertificateValidationCallback(CheckValidationResult);
                }

                /***************************************************************
                * 下面设置HttpWebRequest的相关属性
                * ************************************************************/
                request = (HttpWebRequest)WebRequest.Create(url);
                request.Method = "POST";
                request.Timeout = timeout * 1000;
                //设置POST的数据类型和长度
                logModel.ContentType = request.ContentType = "text/xml";
                byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);
                request.ContentLength = data.Length;

                //是否使用证书
                if (!string.IsNullOrEmpty(certPath))
                {
                    X509Certificate2 cert = new X509Certificate2(AppDomain.CurrentDomain.BaseDirectory + certPath, certPwd);
                    request.ClientCertificates.Add(cert);

                }

                //往服务器写入数据
                reqStream = request.GetRequestStream();
                reqStream.Write(data, 0, data.Length);
                reqStream.Close();

                //获取服务端返回
                response = (HttpWebResponse)request.GetResponse();

                //获取服务端返回数据
                StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
                strResult = sr.ReadToEnd().Trim();
                sr.Close();
                logModel.Result.Body = strResult;
                logModel.Result.IsError = false;
            }
            catch (Exception ex)
            {
                //System.Threading.Thread.ResetAbort();
                strResult = ex.Message;
                logModel.Result.IsError = true;
                logModel.Result.StatusCode = 500;
                logModel.Result.Body = ex.ToJson();

            }
            finally
            {
                //关闭连接和流
                if (response != null)
                {
                    response.Close();
                }
                if (request != null)
                {
                    request.Abort();
                }
            }
            logModel.Result.EndDate = DateTime.Now;
            logModel.Result.TotalMilliseconds = Environment.TickCount - start;
            LogHelper.RequestInfo(logModel);
            return !logModel.Result.IsError;
        }

        /// <summary>
        /// 发送普通请求
        /// </summary>
        /// <param name="host">主机头</param>
        /// <param name="url">地址</param>
        /// <param name="parameters">参数</param>
        /// <param name="charset">字符集</param>
        /// <param name="strResult">返回结果</param>
        /// <param name="isHttps">是否采用Https</param>
        /// <param name="isPost">是否采用post提交</param>
        /// <param name="timeout">超时时间</param>
        /// <returns></returns>
        public static bool SendReq(string url, Dictionary<string, string> parameters, string charset,
            ref string strResult, bool isPost = true, int timeout = 3000)
        {
            int start = Environment.TickCount;
            var logModel = GetRequestLogModel(url, parameters?.ToJson(), isPost);
            //HTTPSQ请求
            ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
            StringBuilder buffer = new StringBuilder();
            //如果需要POST数据   
            if (parameters != null && parameters.Count > 0)
            {
                int i = 0;
                foreach (string key in parameters.Keys)
                {
                    if (i > 0)
                    {
                        buffer.AppendFormat("&{0}={1}", key, parameters[key]);
                    }
                    else
                    {
                        buffer.AppendFormat("{0}={1}", key, parameters[key]);
                    }
                    i++;
                }
                logModel.Query = logModel.Form = parameters.ToJson();
            }

            logModel.Body = buffer.ToString();
            try
            {
                if (!isPost)
                {
                    if (url.IndexOf("?") != -1)
                    {
                        url += "&";
                    }
                    else
                    {
                        url += "?";
                    }
                    url += buffer;
                }

                HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(url);
                myReq.Timeout = timeout;
                myReq.ServicePoint.Expect100Continue = false;
                //myReq.ProtocolVersion = HttpVersion.Version10;
                myReq.Method = isPost ? "POST" : "GET";
                logModel.ContentType = myReq.ContentType = "application/x-www-form-urlencoded;charset=" + charset;
                if (isPost)
                {
                    //myReq.Headers.Add("appAjax", "1");
                    byte[] data = Encoding.GetEncoding(charset).GetBytes(buffer.ToString());
                    using (Stream stream = myReq.GetRequestStream())
                    {
                        stream.Write(data, 0, data.Length);
                    }
                }
                HttpWebResponse HttpWResp = (HttpWebResponse)myReq.GetResponse();
                Stream myStream = HttpWResp.GetResponseStream();
                StreamReader sr = new StreamReader(myStream, Encoding.GetEncoding(charset));
                strResult = sr.ReadToEnd();   //从头读到尾，放到字符串html
                logModel.Result.Body = strResult;
               
            }
            catch (Exception ex)
            {
                strResult = ex.Message;
                logModel.Result.IsError = true;
                logModel.Result.StatusCode = 500;
                logModel.Result.Body = ex.ToJson();
            }
            logModel.Result.EndDate = DateTime.Now;
            logModel.Result.TotalMilliseconds = Environment.TickCount - start;
            LogHelper.RequestInfo(logModel);
            return !logModel.Result.IsError;
        }

        /// <summary>
        /// 发送请求
        /// </summary>
        /// <param name="url"></param>
        /// <param name="data"></param>
        /// <param name="strResult"></param>
        /// <param name="timeout"></param>
        /// <param name="isPost"></param>
        /// <returns></returns>
        public static bool SendWebClient(string url, string data, ref string strResult, int timeout = 3000, bool isPost = true)
        {
            if (string.IsNullOrWhiteSpace(url))
            {
                strResult = "请求地址不存在";
                return false;
            }
            int start = Environment.TickCount;
            var logModel = GetRequestLogModel(url, data, isPost);
            try
            {
                using (WebClientHelper clientHelper = new WebClientHelper())
                {
                    clientHelper.Timeout = timeout;
                    strResult = clientHelper.UploadString(url, isPost ? "POST" : "GET", data);
                }
                logModel.Result.Body = strResult;
              
            }
            catch (Exception ex)
            {
                strResult = ex.Message;
                logModel.Result.IsError = true;
                logModel.Result.StatusCode = 500;
                logModel.Result.Body = ex.ToJson();
            }
            logModel.Result.EndDate = DateTime.Now;
            logModel.Result.TotalMilliseconds = Environment.TickCount - start;
            LogHelper.RequestInfo(logModel);
            return !logModel.Result.IsError;
        }

        /// <summary>
        /// 发送请求
        /// </summary>
        /// <param name="url"></param>
        /// <param name="data"></param>
        /// <param name="strResult"></param>
        /// <param name="timeout"></param>
        /// <param name="isPost"></param>
        /// <returns></returns>
        public static bool SendWebClientAsync(string url, string data, ref string strResult, int timeout = 10000, bool isPost = true)
        {
            int start = Environment.TickCount;
            var logModel = GetRequestLogModel(url, data, isPost);
            try
            {
                using (WebClientHelper clientHelper = new WebClientHelper())
                {
                    Uri address = new Uri(url);
                    clientHelper.Timeout = timeout;
                    clientHelper.UploadStringAsync(address, "POST", data);
                }
               
           
            }
            catch (Exception ex)
            {
              
                logModel.Result.IsError = true;
                logModel.Result.StatusCode = 500;
                logModel.Result.Body = ex.ToJson();
            }
            logModel.Result.EndDate = DateTime.Now;
            logModel.Result.TotalMilliseconds = Environment.TickCount - start;
            LogHelper.RequestInfo(logModel);
            return !logModel.Result.IsError;
            
        }

        public static bool SendWebClientAsync(string url, string data, string userToken, ref string strResult, int timeout = 10000, bool isPost = true)
        {   
            int start = Environment.TickCount;
            var logModel = GetRequestLogModel(url, data, isPost);
            try
            {
                using (WebClientHelper clientHelper = new WebClientHelper())
                {
                    Uri address = new Uri(url);
                    clientHelper.Headers.Add("CONTENT-TYPE", "application/json");
                    clientHelper.Headers.Add(AppHttpContext.TokenKeyName, userToken);
                    clientHelper.Timeout = timeout;
                    clientHelper.UploadStringAsync(address, isPost ? "POST" : "GET", data);
                }
                logModel.Result.IsError = false;
            }
            catch (Exception ex)
            {
                logModel.Result.IsError = true;
                logModel.Result.StatusCode = 500;
                logModel.Result.Body = ex.ToJson();
            }
            logModel.Result.EndDate = DateTime.Now;
            logModel.Result.TotalMilliseconds = Environment.TickCount - start;
            LogHelper.RequestInfo(logModel);
            return !logModel.Result.IsError;
         

        }
        /// <summary>
        /// 写将日志传输给日志系统
        /// </summary>
        /// <param name="url"></param>
        /// <param name="data"></param>
        /// <param name="strResult"></param>
        /// <param name="timeout"></param>
        /// <param name="isPost"></param>
        /// <returns></returns>
        public static bool WriteLogAsync(string url, string data, ref string strResult, int timeout = 10000, bool isPost = true)
        {
            int start = Environment.TickCount;
            var logModel = GetRequestLogModel(url, data, isPost);
            try
            {
                using (WebClientHelper clientHelper = new WebClientHelper())
                {
                    Uri address = new Uri(url);
                    clientHelper.Timeout = timeout;
                    clientHelper.UploadStringAsync(address, "POST", data);
                }
               
            }
            catch (Exception ex)
            {
                logModel.Result.IsError = true;
                logModel.Result.StatusCode = 500;
                logModel.Result.Body = ex.ToJson();
            }
            logModel.Result.EndDate = DateTime.Now;
            logModel.Result.TotalMilliseconds = Environment.TickCount - start;
            LogHelper.RequestInfo(logModel,false);
            return !logModel.Result.IsError;

        }
        /// <summary>
        /// 获取请求日志
        /// </summary>
        /// <param name="url">请求Url</param>
        /// <param name="data">参数</param>
        /// <param name="isPost">是否post</param>
        /// <returns></returns>
        public static HttpLoggingModel GetRequestLogModel(string url, string data, bool isPost = true)
        {
            Uri uri = new Uri(url);
            var logModel = new HttpLoggingModel
            {
                MenuPage = url,
                Host = uri.Host,
                IsHttps = uri.Scheme.ToLower().ToLower().IndexOf("https") >= 0,
                IsAjax = false,
                IsPost = isPost,
                IpAddress = ApplicationEnvironments.Site.ServerAddress,
                SourcePlatform = ApplicationEnvironments.Site.ApplicationName,
                TraceIdentifier = AppHttpContext.Current != null ? AppHttpContext.Current.TraceIdentifier:"",
                Protocol = AppHttpContext.Current!=null?AppHttpContext.Current.Request.Protocol:"",
                StartDate = DateTime.Now,
                ContentType = "",
                Result= new HttpLoggingResultModel()
            };

            return logModel;
        }
    }

    /// <summary>
    /// WebClient 超时设置
    /// </summary>
    public class WebClientHelper : WebClient
    {
        private int _timeout = 10000;
        // 超时时间(毫秒)
        public int Timeout
        {
            get
            {
                return _timeout;
            }
            set
            {
                _timeout = value;
            }
        }
        public WebClientHelper()
        {
           
        }
        public WebClientHelper(int timeout)
        {
            this._timeout = timeout;
        }
      
        protected override WebRequest GetWebRequest(Uri address)
        {
            var result = base.GetWebRequest(address);
            result.Timeout = this._timeout;
            return result;
        }
    }
}

